/** 
 * @defgroup source source
 * source-handling routines
 * @{
 */
 

#include <string.h>
#include "main.h"
#include "prefs.h"
#include "sensor.h"
#include "gui.h"
#include "warp.h"
#include "output.h"
#include "thresh.h"
#include "gstreamer.h"
#include "gfx.h"
#include "source.h"


void src_free(struct video_src *source);


/** local module-structure */
static struct Source
{
    struct video_src *first_source;     /** head of source-list */
    struct video_src *current_source;   /** current source in list */
    gboolean laser_detected;
    unsigned int framecount;
    GtkWidget *textview_caps;   /* to display gStreamer source-capabilities */
    gboolean update_src_gui;             /* update gui if true */
    gboolean update_warp_gui;
}src;



/********************* getter/setter for local variables *********************/
/**
 * set update src-gui boolean
 */
void src_set_updateSrcGui(int v)
{
    src.update_src_gui = v;
}

/**
 * set update warp-gui boolean
 */
void src_set_updateWarpGui(int v)
{
    src.update_warp_gui = v;
}

/**
 * get first source
 */
struct video_src *src_get_first()
{
    if(!(src.first_source))
        _VERBOSE3 printf("%s(): returned NULL pointer!\n", __func__);
    return src.first_source;
}

/**
 * set first source
 */
void src_set_first(struct video_src *s)
{
    src.first_source = s;
}

/**
 * get current source
 */
struct video_src *src_get()
{
    if(!(src.current_source))
        _VERBOSE3 printf("%s(): returned NULL pointer!\n", __func__);
    return src.current_source;
}

/**
 * set current source
 */
void src_set(struct video_src *s)
{
    src.current_source = s;
}

/**
 * get framecount
 */
unsigned int src_get_framecount()
{
    return src.framecount;
}

/**
 * set framecount
 */
void src_set_framecount(unsigned int c)
{
    src.framecount = c;
}
/**
 * get laser-detected flag
 */
gboolean src_get_laserDetected()
{
    return src.laser_detected;
}

/**
 * set laser-detected flag
 */
void src_set_laserDetected(gboolean ld)
{
    src.laser_detected = ld;
}
/************************** GTK-Callbacks **************************/
/**
 * append copy of current source 
 */
gboolean cb_src_copy(GtkWidget * widget)
{
    struct sensor *current_sensor, *new_sensor;
    struct video_src *new_source;
    char tmpstring[1024];

    if(src_get()) {
        _VERBOSE1 printf("cb_source_copy(): copying source \"%s\"\n",
                         src_get()->name);

        /*
         * rebuild name 
         */
        snprintf((char *) &tmpstring, 1023, "%s (%d)",
                 src_get()->name, src_listlen());

        /*
         * create copy of current source 
         */
        new_source = src_new((xmlChar *) & tmpstring,
                                     src_get()->gst_string,
                                     src_get()->tuner);

        /*
         * initialize gstreamer 
         */
        if(gstr_source_init(new_source) == 0)
        {
            /*
             * initialize sensors 
             */
            for(current_sensor = src_get()->first_sensor;
                current_sensor;
                current_sensor = current_sensor->next_sensor) {

                /*
                 * space for new sensor 
                 */
                if((new_sensor = calloc(1, sizeof(struct sensor)))) {

                    /*
                     * copy sensor 
                     */
                    memcpy(new_sensor, current_sensor, sizeof(struct sensor));

                    if(new_sensor->name)
                        new_sensor->name = xmlStrdup(new_sensor->name);
                    
                    if(new_sensor->out_program)
                        new_sensor->out_program = strdup(new_sensor->out_program);
                    
                    /*
                     * append sensor 
                     */
                    new_sensor->next_sensor = NULL;
                    new_source->first_sensor =
                        sensor_append(new_source->first_sensor,
                                      new_sensor);

                }
            }
        }

        /*
         * append source 
         */
        new_source = src_append(src_get_first(), new_source);
        src_set_first(new_source);

        /*
         * refresh gui 
         */
        src.update_src_gui = TRUE;

    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return FALSE;
}

/**
 * "rename-source" button pressed 
 */
gboolean cb_src_rename(GtkWidget * widget)
{
    struct video_src *source = src_get();

    _VERBOSE2 printf("%s()\n", __func__);
    
    if(source) 
    {
        /*
         * set new name 
         */
        gtk_entry_set_text(GTK_ENTRY(glade_xml_get_widget(gui_get_xml(),
                                                          "entry_source_rename_new")),
                           (gchar *) source->name);

        /*
         * set old name 
         */
        gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(gui_get_xml(),
                                                          "label_source_rename_old")),
                           (gchar *) source->name);

        /*
         * select everything & activate edit-widget 
         */
        gtk_widget_activate(glade_xml_get_widget(gui_get_xml(),
                                                 "entry_source_rename_new"));

        /*
         * show name-request window 
         */
        gtk_widget_show(glade_xml_get_widget
                        (gui_get_xml(), "dialog_source_rename"));

    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return FALSE;
}

/**
 * source-renaming has been canceled
 */
gboolean cb_src_rename_cancel_but(GtkWidget * widget)
{

    _VERBOSE2 printf("%s()\n", __func__);
    
    /*
     * hide name-request window 
     */
    gtk_widget_hide(glade_xml_get_widget
                    (gui_get_xml(), "dialog_source_rename"));

    return FALSE;
}

/**
 * source-renaming has been canceled
 */
gboolean cb_src_rename_cancel_del(GtkWidget * widget, GdkEvent * event)
{

    _VERBOSE2 printf("%s()\n", __func__);
    
    /*
     * hide name-request window 
     */
    gtk_widget_hide(glade_xml_get_widget
                    (gui_get_xml(), "dialog_source_rename"));

    return TRUE;
}

/**
 * "OK"-Button in rename-dialog pressed, set new name 
 */
gboolean cb_src_rename_set(GtkWidget * widget)
{
    struct video_src *source = src_get();
    const gchar *new_name;

    _VERBOSE2 printf("%s()\n", __func__);
    
    if(source) {

        /*
         * get name 
         */
        new_name = gtk_entry_get_text(GTK_ENTRY
                                      (glade_xml_get_widget
                                       (gui_get_xml(),
                                        "entry_source_rename_new")));
        /*
         * validate name 
         */

        /*
         * set name 
         */
        source->name = xmlStrdup((xmlChar *) new_name);

        /*
         * refresh sources-menu 
         */
        src_gui_update_pulldown();

        /*
         * close window 
         */
        cb_src_rename_cancel_but(NULL);

        _VERBOSE1 printf("%s(): renamed to \"%s\"\n",
                         __func__, new_name);
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return FALSE;
}

/**
 * main drawing-function called whenever we are idle
 * (our main priority is not the preview, but the detection)
 * @param source - current video source
 * @result always TRUE to get called again
 * @note this is intended to be active only once. Upon change of source,
 *       disconnect and connect for new-source
 */
gboolean cb_source_idle_function(struct video_src *source)
{
    #define DOT_WIDTH 10
    GdkPixbuf *pixbuf_in = NULL, *pixbuf_out = NULL, *src_pixbuf = NULL;
    guchar *input = NULL, *output = NULL;
    int tmp_x,tmp_y,tmp_w,tmp_h;
    char tempchar[255];
    
    
    _VERBOSE6 printf("%s()\n", __func__);
    
    
    /* process gtk-events */
    while (gtk_events_pending()) {
        gtk_main_iteration();
    }
    
    /* update gui? */
    if(src.update_src_gui)
    {
        src_gui_update();
        src.update_src_gui = 0;
    }
    
    if(src.update_warp_gui)
    {
        warp_gui_update();
        src.update_warp_gui = 0;
    }
    
    /*
     * only draw if we should and if we have something to draw 
     */
    if(source && (source == src_get()) &&
        source->gst_input_pixbuf &&
           source->input_pixbuf &&
           source->output_pixbuf &&
           (source->draw_dst
            || source->draw_source))
    {
        
        input = gdk_pixbuf_get_pixels(source->gst_input_pixbuf);
        output = gdk_pixbuf_get_pixels(source->output_pixbuf);
        src_pixbuf = source->gst_input_pixbuf;

        
        /*
         * draw output preview ?
         */
        if((source->draw_dst && gui_get_da_dst())) 
        {
            _VERBOSE6 printf("%s(): Draw output preview\n", __func__);
            
            /*
             * warp image 
             */
            if(sensor_get()) 
            {
                
                warp_image(input, output,
                           source->width,
                           source->height,
                           sensor_get()->wrp_x1,
                           sensor_get()->wrp_y1,
                           sensor_get()->wrp_x2,
                           sensor_get()->wrp_y2,
                           sensor_get()->wrp_x3,
                           sensor_get()->wrp_y3,
                           sensor_get()->wrp_x4,
                           sensor_get()->wrp_y4);

                /*
                 * threshold image 
                 */
                if(thresh_get_do()) 
                {
                    thresh_frame(output, output,
                                    source->width *
                                    source->height * 3,
                                    sensor_get()->thr_threshold,
                                    sensor_get()->thr_R,
                                    sensor_get()->thr_G,
                                    sensor_get()->thr_B);

                    /*
                     * track pointer 
                     */
                    g_track_xy(output);
                    
                    
                    /* laser detected ... */
                    if(src.laser_detected) 
                    {
                        
                        /*
                         * set calced mouse-position as label
                         */
                        snprintf((char *) &tempchar, 254, "%d",
                                 sensor_get()->x);
                        gtk_label_set_text(GTK_LABEL
                                           (glade_xml_get_widget
                                            (gui_get_xml(), "label_x")),
                                           g_locale_to_utf8((gchar *) &tempchar, -1, NULL, NULL, NULL));
                                                
                        snprintf((char *) &tempchar, 254, "%d",
                                 sensor_get()->y);
                        gtk_label_set_text(GTK_LABEL
                                           (glade_xml_get_widget
                                            (gui_get_xml(), "label_y")),
                                           g_locale_to_utf8((gchar *) &tempchar, -1, NULL, NULL, NULL));
                                                
                        /* detection "light" */
                        gtk_widget_hide(glade_xml_get_widget(gui_get_xml(),
                                    "image_no"));
                        gtk_widget_show(glade_xml_get_widget(gui_get_xml(),
                                    "image_yes"));
                    
                    
                        _VERBOSE4 printf("%s(): %d/%d\n",
                                    __func__, sensor_get()->x, sensor_get()->y);
                    }
                    else
                    /* no laser currently detected */
                    {
                        gtk_widget_hide(glade_xml_get_widget(gui_get_xml(),
                        "image_yes"));
                        gtk_widget_show(glade_xml_get_widget(gui_get_xml(),
                        "image_no"));
                    }
                    
                }

                /*
                 * scale output pixbuf 
                 */
                if(gui_get_da_dst()->allocation.width > 0 &&
                   gui_get_da_dst()->allocation.height > 0)
                {
                    pixbuf_out =
                        gdk_pixbuf_scale_simple(source->
                                                output_pixbuf,
                                                gui_get_da_dst()->
                                                allocation.width,
                                                gui_get_da_dst()->
                                                allocation.height,
                                                GDK_INTERP_BILINEAR);
                }
                else
                    pixbuf_out = NULL;

                if(pixbuf_out) 
                {
                    gdk_draw_pixbuf(gui_get_da_dst()->window,
                                    gui_get_da_dst()->style->
                                    fg_gc[GTK_WIDGET_STATE
                                          (gui_get_da_dst())],
                                    pixbuf_out, 0, 0, 0, 0,
                                    gui_get_da_dst()->allocation.width,
                                    gui_get_da_dst()->allocation.
                                    height, GDK_RGB_DITHER_NORMAL, 0, 0);

                    g_object_unref(G_OBJECT(pixbuf_out));
                }
            }

            /*
             * reset flag 
             */
            source->draw_dst = FALSE;
        }

        
        /*
         * draw input preview ?
         */
        if(source->draw_source && gui_get_da_src()) 
        {
     
            _VERBOSE6 printf("%s(): Draw input preview\n", __func__);
            
            /* copy preview */
            gdk_pixbuf_copy_area(src_pixbuf, 0, 0,
                         source->width,
                         source->height,
                         source->input_pixbuf, 0, 0);
            input = gdk_pixbuf_get_pixels(source->input_pixbuf);
            
            /* draw warp-coordinates */
            if((sensor_get()->wrp_x1-DOT_WIDTH/2) < 0)
            {
                tmp_x = 0;
            }
            else
                tmp_x = sensor_get()->wrp_x1-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_x1+DOT_WIDTH/2) > 
                    source->width)
            {
                tmp_w = source->width - 
                            sensor_get()->wrp_x1;
            }
            else
                tmp_w = DOT_WIDTH;
            
            
            if((sensor_get()->wrp_y1-DOT_WIDTH/2) < 0)
            {
                tmp_y = 0;
            }
            else
                tmp_y = sensor_get()->wrp_y1-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_y1+DOT_WIDTH/2) >
                    source->height)
            {
                tmp_h = source->height -
                            sensor_get()->wrp_y1;
            }
            else
                tmp_h = DOT_WIDTH;
            
            
            g_drawBox_invert(input, source->width, tmp_x, tmp_y, 
                        tmp_w, tmp_h);
            
            
            
            if((sensor_get()->wrp_x2-DOT_WIDTH/2) < 0)
            {
                tmp_x = 0;
            }
            else
                tmp_x = sensor_get()->wrp_x2-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_x2+DOT_WIDTH/2) > 
                    source->width)
            {
                tmp_w = source->width - 
                            sensor_get()->wrp_x2;
            }
            else
                tmp_w = DOT_WIDTH;
            
            
            if((sensor_get()->wrp_y2-DOT_WIDTH/2) < 0)
            {
                tmp_y = 0;
            }
            else
                tmp_y = sensor_get()->wrp_y2-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_y2+DOT_WIDTH/2) >
                    source->height)
            {
                tmp_h = source->height -
                            sensor_get()->wrp_y2;
            }
            else
                tmp_h = DOT_WIDTH;
            
            g_drawBox_invert(input, source->width, tmp_x, tmp_y, 
                        tmp_w, tmp_h);
            
            
            
            if((sensor_get()->wrp_x3-DOT_WIDTH/2) < 0)
            {
                tmp_x = 0;
            }
            else
                tmp_x = sensor_get()->wrp_x3-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_x3+DOT_WIDTH/2) > 
                    source->width)
            {
                tmp_w = source->width - 
                            sensor_get()->wrp_x3;
            }
            else
                tmp_w = DOT_WIDTH;
            
            
            if((sensor_get()->wrp_y3-DOT_WIDTH/2) < 0)
            {
                tmp_y = 0;
            }
            else
                tmp_y = sensor_get()->wrp_y3-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_y3+DOT_WIDTH/2) >
                    source->height)
            {
                tmp_h = source->height -
                            sensor_get()->wrp_y2;
            }
            else
                tmp_h = DOT_WIDTH;
            
            g_drawBox_invert(input, source->width, tmp_x, tmp_y, 
                        tmp_w, tmp_h);
            
            
            
            if((sensor_get()->wrp_x4-DOT_WIDTH/2) < 0)
            {
                tmp_x = 0;
            }
            else
                tmp_x = sensor_get()->wrp_x4-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_x4+DOT_WIDTH/2) > 
                    source->width)
            {
                tmp_w = source->width - 
                            sensor_get()->wrp_x2;
            }
            else
                tmp_w = DOT_WIDTH;
            
            
            if((sensor_get()->wrp_y4-DOT_WIDTH/2) < 0)
            {
                tmp_y = 0;
            }
            else
                tmp_y = sensor_get()->wrp_y4-DOT_WIDTH/2;
            
            if((sensor_get()->wrp_y4+DOT_WIDTH/2) >
                    source->height)
            {
                tmp_h = source->height -
                            sensor_get()->wrp_y4;
            }
            else
                tmp_h = DOT_WIDTH;
            
            g_drawBox_invert(input, source->width, tmp_x, tmp_y, 
                        tmp_w, tmp_h);
            
            
            /*
             * draw warped box 
             */
            if(sensor_get()) 
            {
                g_drawLine_invert(input, source->width,
                         source->height,
                         sensor_get()->wrp_x1,
                         sensor_get()->wrp_y1,
                         sensor_get()->wrp_x2,
                         sensor_get()->wrp_y2);
                g_drawLine_invert(input, source->width,
                         source->height,
                         sensor_get()->wrp_x2,
                         sensor_get()->wrp_y2,
                         sensor_get()->wrp_x3,
                         sensor_get()->wrp_y3);
                g_drawLine_invert(input, source->width,
                         source->height,
                         sensor_get()->wrp_x3,
                         sensor_get()->wrp_y3,
                         sensor_get()->wrp_x4,
                         sensor_get()->wrp_y4);
                g_drawLine_invert(input, source->width,
                         source->height,
                         sensor_get()->wrp_x4,
                         sensor_get()->wrp_y4,
                         sensor_get()->wrp_x1,
                         sensor_get()->wrp_y1);
            }


            /*
             * scale input pixbuf 
             */
            if(gui_get_da_src()->allocation.width > 0 &&
               gui_get_da_src()->allocation.height > 0)
                pixbuf_in = gdk_pixbuf_scale_simple(source->input_pixbuf,
                                                    gui_get_da_src()->
                                                    allocation.width,
                                                    gui_get_da_src()->
                                                    allocation.height,
                                                    GDK_INTERP_BILINEAR);
            else
                pixbuf_in = NULL;

            if(pixbuf_in) 
            {
                gdk_draw_pixbuf(gui_get_da_src()->window,
                                gui_get_da_src()->style->
                                fg_gc[GTK_WIDGET_STATE
                                      (gui_get_da_src())], pixbuf_in,
                                0, 0, 0, 0,
                                gui_get_da_src()->allocation.width,
                                gui_get_da_src()->allocation.height,
                                GDK_RGB_DITHER_NORMAL, 0, 0);

                g_object_unref(G_OBJECT(pixbuf_in));
            }
            
            /*
             * reset flag 
             */
            source->draw_source = FALSE;
         
   
        }
        
        /* increase framecount */
        src.framecount += 1;
    }

    
    return source->idle_func;
}

/**
 * different video-source selected 
 */
gboolean cb_src_changed(GtkWidget * widget)
{
    struct video_src *new_source;

    
    _VERBOSE2 printf("%s()\n", __func__);

    
    /*
     * get newly selected source 
     */
    if((new_source =
        src_get_n(gtk_combo_box_get_active(GTK_COMBO_BOX(widget)))))
    {

        /* another source? */
        if(new_source != src_get()) 
            {
                
            

            /*
             * stop capture of current-source 
             */
            if(src_get()->do_capture)
                gstr_capture_stop(src_get());

            /*
             * disconnect callback from sink 
             */
            g_signal_handlers_disconnect_by_func(src_get()->gst_sink,
                                                 cb_gstr_frame_received,
                                                 NULL);

            /* disconnect idle-function */
            //g_idle_remove_by_data(src_get());
            src_get()->idle_func = FALSE;
            new_source->idle_func = TRUE;
            
            /*
             * set new current-source 
             */
            src_set(new_source);
            _VERBOSE1 printf("%s(): %s\n", __func__, new_source->name);

            /*
             * set new current-sensor 
             */
            sensor_set(new_source->first_sensor);
            _VERBOSE1 printf("%s(): Sensor: %s\n", __func__,
                             new_source->first_sensor->name);


            /* add new idle-function */
            //g_idle_add((GSourceFunc) cb_source_idle_function, (gpointer) src_get());
            g_timeout_add(100, (GSourceFunc) cb_source_idle_function, (gpointer) src.current_source);
            
            /*
             * add fakesink callback function 
             */
            g_signal_connect(new_source->gst_sink, "handoff",
                             G_CALLBACK(cb_gstr_frame_received),
                             (gpointer) new_source);

            /*
             * update gui 
             */
            src.update_src_gui = TRUE;

            /*
             * change state 
             */
            gstr_capture_start(src_get());
            gstr_capture_stop(src_get());
            src_get()->draw_source = TRUE;
            src_get()->draw_dst = TRUE;
            
            /* reset framecount */
            src.framecount = 0;

        }
        else
        {
            _VERBOSE1 printf("%s(): source already set.\n", __func__);
        }
    }
    else
    {
        _VERBOSE1 printf("%s(): illegal source number: %d\n",
                         __func__,
                        gtk_combo_box_get_active(GTK_COMBO_BOX(widget)));
    }
    
    return FALSE;
}

/**
 * remove-source button pressed 
 */
gboolean cb_src_remove(GtkWidget * widget)
{
    struct video_src *next, *previous, *source = src_get();
    int pos;

    _VERBOSE2 printf("%s()\n", __func__);
    
    /*
     * get sandwich sources 
     */
    pos = src_listpos(source);
    previous = src_get_n(pos - 1);
    next = source->next_source;

    if(previous || next) 
    {
        /*
         * disconnect callback from sink 
         */
        g_signal_handlers_disconnect_by_func(src_get()->gst_sink,
                                             cb_gstr_frame_received,
                                             NULL);

        /* disconnect idle-function */
        //g_idle_remove_by_data(src_get());
        src_get()->idle_func = FALSE;
    
        /*
         * take current source out of the link 
         */
        if(previous)
            previous->next_source = next;
        else
            /*
             * if there's no previous source, we got the list-head 
             */
            src_set_first(next);

        /*
         * set new current-source 
         */
        if(next) 
        {
            src_set(next);
            sensor_set(next->first_sensor);

        }
        else 
        {
            src_set(previous);
            if(previous)
                sensor_set(previous->first_sensor);
            else
                sensor_set(NULL);

            pos--;

        }

        gtk_combo_box_set_active(GTK_COMBO_BOX
                                     (glade_xml_get_widget
                                      (gui_get_xml(),
                                       "combobox_sources")), pos);
        
        /*
         * free this source 
         */
        src_free(source);

        /*
         * refresh gui 
         */
        src.update_src_gui = TRUE;
    }
    else
    {
        gui_dialog("Last source can't be deleted");
    }
    
    return FALSE;
}

/**
 * add new-source button pressed 
 */
gboolean cb_src_add(GtkWidget * widget)
{
#define DEFAULT_PIPELINE "videotestsrc ! video/x-raw-rgb,width=720,height=576,bpp=24 ! fakesink"
#define DEFAULT_SENSOR_NAME "sensor"
#define DEFAULT_SENSOR_WIDTH 1024
#define DEFAULT_SENSOR_HEIGHT 768

    struct video_src *new_source;
    struct sensor *new_sensor;

    char tmpstring[255];

    _VERBOSE2 printf("%s()\n", __func__);
    
    /*
     * build new name 
     */
    snprintf((char *) &tmpstring, 254, "New #%d", src_listlen() + 1);
    
    
    /*
     * create new source 
     */
    if((new_source = src_new((xmlChar *) & tmpstring,
                                     (xmlChar *) DEFAULT_PIPELINE, NULL)))
    {

        /*
         * initialize gstreamer 
         */
        if(gstr_source_init(new_source) == 0)
        {
            
            /*
             * space for new sensor 
             */
            if((new_sensor = calloc(1, sizeof(struct sensor)))) {
    
                /*
                 * init default sensor 
                 */
                new_sensor->name = xmlStrdup((xmlChar *) DEFAULT_SENSOR_NAME);
                new_sensor->wrp_x1 = 10;
                new_sensor->wrp_y1 = 10;
                new_sensor->wrp_x2 = 100;
                new_sensor->wrp_y2 = 10;
                new_sensor->wrp_x3 = 100;
                new_sensor->wrp_y3 = 100;
                new_sensor->wrp_x4 = 10;
                new_sensor->wrp_y4 = 100;
                new_sensor->out_width = DEFAULT_SENSOR_WIDTH;
                new_sensor->out_height = DEFAULT_SENSOR_HEIGHT;
    
                /*
                 * append sensor 
                 */
                new_source->first_sensor =
                    sensor_append(new_source->first_sensor, new_sensor);
    
                /*
                 * append source 
                 */
                new_source = src_append(src_get_first(), new_source);
                src_set_first(new_source);
    
                /*
                 * refresh gui 
                 */
                src_gui_update_pulldown();
    
                /*
                 * activate new source 
                 */
                gtk_combo_box_set_active(GTK_COMBO_BOX
                                         (glade_xml_get_widget
                                          (gui_get_xml(),
                                           "combobox_sources")),
                                         src_listlen()-1);
    
                _VERBOSE1 printf("source_add(): added \"%s\"\n", (char *) &tmpstring);
            }
            /*
             * free stuff 
             */
            else {
                printf("ERROR: No more memory for new sensor...\n");
                src_free(new_source);
            }
        }
        else {
            printf("ERROR: Failed to initialize gStreamer for source...\n");
            src_free(new_source);
        }
    }
    else {
        printf("ERROR: Failed to init new source...\n");
    }
    
    return FALSE;
}

/**
 * switch-rb button toggled
 */
gboolean cb_switchrb_toggled(GtkWidget *widget)
{
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(src.current_source)
    {
        if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
            src.current_source->swap_rb = TRUE;
        else
            src.current_source->swap_rb = FALSE;
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return TRUE;
}

/**
 * click into output-preview
 */
gboolean cb_drawingarea_preview_click(GtkWidget * widget, GdkEventButton * event)
{
    int x, y;
    unsigned char *buffer;
    GdkColor color;

    
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(src.current_source)
    {
        
        x = (int) (event->x / (double) widget->allocation.width *
                   (double) src.current_source->width);
        y = (int) (event->y / (double) widget->allocation.height *
                   (double) src.current_source->height);
    
        switch (gtk_notebook_get_current_page
                (GTK_NOTEBOOK
                 (glade_xml_get_widget(gui_get_xml(), "notebook_main"))))
        {
    
            /*
             * color-threshold 
             */
        case 1:
            if(thresh_get_do() == FALSE)
            {
                /*
                 * change threshold color 
                 */
                if(src.current_source->output_pixbuf) {
                    /*
                     * set r-g-b for this source 
                     */
                    buffer =
                        gdk_pixbuf_get_pixels(src.current_source->output_pixbuf);
        
                    sensor_get()->thr_R = (unsigned char)
                        buffer[(src.current_source->width) *3 * y + x * 3];
                    sensor_get()->thr_G =
                        buffer[(src.current_source->width) *3 * y + x * 3 + 1];
                    sensor_get()->thr_B =
                        buffer[(src.current_source->width) *3 * y + x * 3 + 2];
        
                    /*
                     * set color-selector 
                     */
                    color.red = (sensor_get()->thr_R) *65535 / 255;
                    color.green = (sensor_get()->thr_G) *65535 / 255;
                    color.blue = (sensor_get()->thr_B) *65535 / 255;
        
                    gtk_color_button_set_color(GTK_COLOR_BUTTON
                                               (glade_xml_get_widget
                                                (gui_get_xml(),
                                                 "colorbutton_thresh")), &color);
        
                }
            }
            break;
    
        default:
            break;
        }
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return TRUE;
}
/**
 * click into input-preview
 */
gboolean cb_drawingarea_input_click(GtkWidget * widget, GdkEventButton * event)
{
    int x, y;
    unsigned char *buffer;
    GdkColor color;
    int *wrp_x, *wrp_y;
    int delta_x, delta_y;

    
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(src.current_source)
    {
        
        /* position in gStreamer image */
        x = (int) (event->x / (double) widget->allocation.width *
                   (double) src.current_source->width);
        y = (int) (event->y / (double) widget->allocation.height *
                   (double) src.current_source->height);
    
        switch ((int) gtk_notebook_get_current_page(GTK_NOTEBOOK
                 (glade_xml_get_widget(gui_get_xml(), "notebook_main"))))
        {
    
    
            /*
             * color-threshold 
             */
            case 1:
                
                /*
                 * change threshold color 
                 */
                if(src.current_source->input_pixbuf) 
                {
                    
                    /*
                     * set r-g-b for this source 
                     */
                    buffer =
                        gdk_pixbuf_get_pixels(src.current_source->input_pixbuf);
        
                    sensor_get()->thr_R = (unsigned char)
                        buffer[(src.current_source->width) *3 * y + x * 3];
                    sensor_get()->thr_G =
                        buffer[(src.current_source->width) *3 * y + x * 3 + 1];
                    sensor_get()->thr_B =
                        buffer[(src.current_source->width) *3 * y + x * 3 + 2];
        
                    /*
                     * set color-selector 
                     */
                    color.red = (sensor_get()->thr_R) * 65535 / 255;
                    color.green = (sensor_get()->thr_G) * 65535 / 255;
                    color.blue = (sensor_get()->thr_B) * 65535 / 255;
        
                    gtk_color_button_set_color(GTK_COLOR_BUTTON
                                               (glade_xml_get_widget
                                                (gui_get_xml(),
                                                 "colorbutton_thresh")), &color);
                    /*
                     * redraw output 
                     */
                    src.current_source->draw_dst = TRUE;
        
                }
                break;
            
                
                /*
                 * change warp-frame 
                 */
            case 0:
            case 2:
                /*
                 * find nearest point 
                 */
                wrp_x = &sensor_get()->wrp_x1;
                wrp_y = &sensor_get()->wrp_y1;
                delta_x = abs(x - wrp_x[0]);
                delta_y = abs(y - wrp_y[0]);
        
                if(delta_x + delta_y >
                   (abs(x - sensor_get()->wrp_x2) +
                    abs(y - sensor_get()->wrp_y2)))
                {
                    wrp_x = &sensor_get()->wrp_x2;
                    wrp_y = &sensor_get()->wrp_y2;
                    delta_x = abs(x - wrp_x[0]);
                    delta_y = abs(y - wrp_y[0]);
                }
                
                if(delta_x + delta_y >
                   (abs(x - sensor_get()->wrp_x3) +
                    abs(y - sensor_get()->wrp_y3)))
                {
                    wrp_x = &sensor_get()->wrp_x3;
                    wrp_y = &sensor_get()->wrp_y3;
                    delta_x = abs(x - wrp_x[0]);
                    delta_y = abs(y - wrp_y[0]);
                }
                
                if(delta_x + delta_y >
                   (abs(x - sensor_get()->wrp_x4) +
                    abs(y - sensor_get()->wrp_y4)))
                {
                    wrp_x = &sensor_get()->wrp_x4;
                    wrp_y = &sensor_get()->wrp_y4;
                    delta_x = abs(x - wrp_x[0]);
                    delta_y = abs(y - wrp_y[0]);
                }
        
                /*
                 * adjust coordinate 
                 */
                wrp_x[0] = x;
                wrp_y[0] = y;
                sensor_get()->wrp_gr_x = wrp_x;
                sensor_get()->wrp_gr_y = wrp_y;
        
                /*
                 * update gui 
                 */
                src.update_warp_gui = TRUE;
                
        
                /*
                 * redraw 
                 */
                src.current_source->draw_source = TRUE;
                src.current_source->draw_dst = TRUE;
                break;
                
                
            default:
                _ERROR printf("cb_drawingarea_click(): no click-action defined.\n");
                break;
        }
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return TRUE;
}

/**
 * mouse-motion above the input-preview
 */
gboolean cb_drawingarea_input_motion(GtkWidget * widget, GdkEventButton * event)
{
    static unsigned int framecount;
    int menu;
    
    
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(src.current_source && sensor_get())
    {
        
        if(framecount != src.framecount)
        {
            framecount = src.framecount;
            
            menu = ((int) gtk_notebook_get_current_page(GTK_NOTEBOOK
                     (glade_xml_get_widget(gui_get_xml(), "notebook_main"))));
            
            /* mouse-button pressed ? */
            if ((event->state & GDK_BUTTON1_MASK) && 
                    sensor_get() != NULL && src.current_source != NULL &&
                    (menu == 0 || menu == 2))
            {
        
                /* do we hold an edge ? */
                if((sensor_get()->wrp_gr_x != NULL) &&
                   (sensor_get()->wrp_gr_y != NULL))
                {
                    
                    /* inside valid area? */
                    if(event->x > 0 && event->y > 0 &&
                        event->x <= widget->allocation.width &&
                        event->y <= widget->allocation.height)
                    {
                        *sensor_get()->wrp_gr_x = 
                                (int) (event->x / (double) widget->allocation.width *
                                (double) src.current_source->width);
                        
                        *sensor_get()->wrp_gr_y =
                                (int) (event->y / (double) widget->allocation.height *
                               (double) src.current_source->height);
                        
                        /* redraw */
                        src.update_warp_gui = TRUE;
                        src.current_source->draw_source =
                        src.current_source->draw_dst = TRUE;
                    }
                }
            }
        }
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return TRUE;
}

/**
 * start/stop preview, "Capture" Button toggled 
 */
gboolean cb_capture_toggled(GtkWidget * widget)
{
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
        /*
         * start playing 
         */
        gstr_capture_start(src.current_source);
    }
    else {
        /*
         * stop playing 
         */
        gstr_capture_stop(src.current_source);
    }
    
    return TRUE;
}


/**
 * disable-source checkbutton toggled
 */
gboolean cb_src_disabled(GtkWidget *widget)
{
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(src.current_source)
    {
        src.current_source->disabled = 
            gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
    }
        
    return TRUE;
}
/**
 * input-preview was exposed
 */
gboolean cb_preview_src_exposed(GtkWidget * widget,
                             GdkEventExpose * event)
{
    _VERBOSE2 printf("%s()\n", __func__);
    
    
    if(src.current_source)
    {
      
        src.current_source->draw_source = TRUE;
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return TRUE;
}

/**
 * processed-preview was exposed
 */
gboolean cb_preview_dst_exposed(GtkWidget * widget,
                             GdkEventExpose * event)
{
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(src.current_source) 
    {
        
        src.current_source->draw_dst = TRUE;
    }
    else
    {
        _ERROR printf("%s(): NULL-pointer received!\n", __func__);
    }
    return TRUE;
}

/************************** Module **************************/


/**
 * free a source structure completly, so the pointer becomes invalid 
 */
void src_free(struct video_src *source)
{
    if(source) {
        _VERBOSE1 printf("%s(): freeing \"%s\"\n", __func__, source->name);

        /*
         * free gstreamer stuff 
         */
        gstr_source_free(source);

        /*
         * free gdk-stuff 
         */
        if(GDK_IS_PIXBUF(source->input_pixbuf))
            g_object_unref(source->input_pixbuf);
        if(GDK_IS_PIXBUF(source->output_pixbuf))
            g_object_unref(source->output_pixbuf);

        /*
         * freeing sensors 
         */
        sensor_list_free(source->first_sensor);

        free(source);
    }
}

/**
 * initialize preview-gui
 */
int src_gui_init()
{
    GladeXML *xml = gui_get_xml();
    
    
    
    _VERBOSE2 printf("%s()\n", __func__);
    
    /*g_signal_connect(G_OBJECT(gui_get_da_src()), "expose_event",
                     G_CALLBACK(cb_preview_src_exposed), NULL);
    
    g_signal_connect(G_OBJECT(gui_get_da_dst()), "expose_event",
                     G_CALLBACK(cb_preview_dst_exposed), NULL);
    
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "togglebutton_capture")), "toggled",
                     G_CALLBACK(cb_capture_toggled), NULL);

    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "drawingarea_input")),
                     "button-press-event", G_CALLBACK(cb_drawingarea_input_click),
                     NULL);
                     
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "drawingarea_output")),
                     "button-press-event", G_CALLBACK(cb_drawingarea_preview_click),
                     NULL);
    
    g_signal_connect (G_OBJECT(glade_xml_get_widget(xml,
                 "drawingarea_input")), "motion-notify-event", G_CALLBACK
                      (cb_drawingarea_input_motion), NULL);
      
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "button_source_remove")), "clicked",
                     G_CALLBACK(cb_src_remove), NULL);
                     
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "button_source_add")), "clicked",
                     G_CALLBACK(cb_src_add), NULL);
                     
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "button_source_copy")), "clicked",
                     G_CALLBACK(cb_src_copy), NULL);

    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "button_source_rename")), "clicked",
                     G_CALLBACK(cb_src_rename), NULL);

    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "button_source_rename_cancel")),
                     "clicked", G_CALLBACK(cb_src_rename_cancel_but),
                     NULL);

    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "button_source_rename_ok")),
                     "clicked", G_CALLBACK(cb_src_rename_set), NULL);

    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "dialog_source_rename")),
                     "delete-event", G_CALLBACK(cb_src_rename_cancel_del),
                     NULL);

    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "combobox_sources")), "changed",
                     G_CALLBACK(cb_src_changed), NULL);
                     
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "checkbutton_redblue")), "toggled",
                     G_CALLBACK(cb_switchrb_toggled), NULL);
                     
    g_signal_connect(G_OBJECT
                     (glade_xml_get_widget
                      (xml, "checkbutton_disabled")), "toggled",
                     G_CALLBACK(cb_src_disabled), NULL);*/
                     
    /*
     * add idle-function 
     */
    //g_idle_add((GSourceFunc) cb_source_idle_function, (gpointer) src.current_source);
    g_timeout_add(100, (GSourceFunc) cb_source_idle_function, (gpointer) src.current_source);
    src.current_source->idle_func = TRUE;
    
    /* get widgets */
    src.textview_caps = glade_xml_get_widget(xml, "textview_caps");
    
    return 0;
}

/**
 * initialize video-module once
 */
int src_init()
{
    _VERBOSE2 printf("%s()\n", __func__);
    memset(&src, 0, sizeof(struct Source));
       
    return 0;
}
/*
 * free sources 
 */
void src_cleanup()
{
    struct video_src *tmp_source, *current_source;
    
    for(current_source = src_get_first(); current_source;) {

        tmp_source = current_source->next_source;
        src_free(current_source);
        current_source = tmp_source;

    }
}

/**
 * destroy-handler for gdk_pixbuf_new_from_data() 
 */
void free_my_pixbuf(guchar * pixels, gpointer data)
{
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(pixels)
        free(pixels);
}


/**
 * set and register capabilities of this video-source 
 */
void src_caps_init(struct video_src *source, GstBuffer * buffer)
{
    const GstStructure *cap_struct;
    unsigned char *mem_buffer = NULL;


    _VERBOSE2 printf("%s()\n", __func__);
    

    source->caps = GST_BUFFER_CAPS(buffer);

    
    if((cap_struct = gst_caps_get_structure(source->caps, 0)))
    {

        /*
         * save attribtues of video-stream 
         */
        gst_structure_get_int(cap_struct, "width", &source->width);
        gst_structure_get_int(cap_struct, "height", &source->height);
        gst_structure_get_int(cap_struct, "bpp", &source->bpp);
        gst_structure_get_int(cap_struct, "depth", &source->depth);
        gst_structure_get_int(cap_struct, "endianness", &source->endianess);
        gst_structure_get_int(cap_struct, "red_mask", &source->red_mask);
        gst_structure_get_int(cap_struct, "green_mask", &source->green_mask);
        gst_structure_get_int(cap_struct, "blue_mask", &source->blue_mask);
    
        /*
         * free output-buffer if there is one 
         */
        if(GDK_IS_PIXBUF(source->output_pixbuf))
        {
            g_object_unref(source->output_pixbuf);
            source->output_pixbuf = NULL;
        }        
    
        /*
         * allocate output-buffer 
         */
        if((mem_buffer = calloc(1, source->width * source->height * 3))) 
        {
                 
            /*
             * create pixbuf from output-buffer 
             */
            source->output_pixbuf =
                gdk_pixbuf_new_from_data(mem_buffer,
                                         GDK_COLORSPACE_RGB,
                                         FALSE, 8, source->width, source->height,
                                         (source->width) * 3, free_my_pixbuf, NULL);
        
            /*
             * free input-buffer if there was one 
             */
            if(GDK_IS_PIXBUF(source->input_pixbuf))
            {
                g_object_unref(source->input_pixbuf);
                source->input_pixbuf = NULL;
            }

            
            /*
             * create new input buffer 
             */
            source->input_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
                                                source->width, source->height);
        
            if(source->gst_input_pixbuf)
                g_object_unref(source->gst_input_pixbuf);
            
            /* create new buffer for gStreamer-input */
            source->gst_input_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8,
                                                  source->width, source->height);

            
            _VERBOSE2 printf("%s(): Got new capabilities: \"%s\"\n",
                             __func__, gst_caps_to_string(source->caps));
        }
        else
        {
            /*
             * fatal 
             */
            gui_dialog("Could not allocate memory to buffer frames!");
        }
    }
    else
    {
        _VERBOSE2 printf("%s(): Failed to get capabilities\n", __func__);
    }
}

/**
 * allocate and fill new video_src structure - free with src_free()
 */
struct video_src *src_new(xmlChar *name, xmlChar *pipeline,
                                  xmlChar * tuner)
{
    struct video_src *source;

    _VERBOSE1 printf("%s(): New source \"%s\"\n", __func__, name);
    
    if(name && pipeline)
    {
        if((source = calloc(1, sizeof(struct video_src)))) 
        {

            /*
             * copy xml-properties to structure 
             */
            source->name = xmlStrdup(name);
            source->gst_string = xmlStrdup(pipeline);
            if(tuner)
                source->tuner = xmlStrdup(tuner);
            return source;
        }
    }
    else
    {
        _ERROR printf("%s(): can't create source without name or" \
                      " gStreamer-pipeline!\n", __func__);
    }

    return NULL;
}

/**
 * initialize source structure from XML-Node
 */
struct video_src *src_init_from_xml(xmlNodePtr source_xml)
{
    struct video_src *result = NULL;
    xmlNode *tmp_child;

    _VERBOSE1 printf("%s(): (%s, %s, %s)\n",
                    __func__,
                     xmlGetProp(source_xml, (xmlChar *) "name"),
                     xmlGetProp(source_xml, (xmlChar *) "gst_string"),
                     xmlGetProp(source_xml, (xmlChar *) "tuner"));

    if((result =
        src_new(xmlGetProp(source_xml, (xmlChar *) "name"),
                        xmlGetProp(source_xml, (xmlChar *) "gst_string"),
                        xmlGetProp(source_xml, (xmlChar *) "tuner"))))
    {
        
        /* source disabled? */
        if(xmlGetProp(source_xml, (xmlChar *) "disabled"))
        {
            result->disabled = atoi((char *) 
                                xmlGetProp(source_xml, (xmlChar *) "disabled"));
        }
        else
        {
            result->disabled = TRUE;
        }
                

        if(xmlGetProp(source_xml, (xmlChar *) "swap-rb"))
        {
            result->swap_rb = atoi((char *) xmlGetProp(source_xml, (xmlChar *) "swap-rb"));
        }
                
        /*
         * initialize gstreamer 
         */
        if(gstr_source_init(result) == 0)
        {
            gui_dialog("Failed to initialize gStreamer pipeline for source \"%s\"",
                result->name);
        }
        
        /*
         * walk all childs
         */
        for(tmp_child = xmlGetLastChild(source_xml); tmp_child;
            tmp_child = tmp_child->prev) 
        {
            
            /* child is a sensor? */
            if(xmlStrcmp(tmp_child->name, (xmlChar *) "sensor") == 0) 
            {
                
                /*
                 * append sensor to this source's sensor-list 
                 */
                result->first_sensor =
                    sensor_append_from_xml(result->first_sensor,
                                      tmp_child);
                
                /* set this sensor as current sensor */
                if(!sensor_get())
                    sensor_set(result->first_sensor);
            }
        }
       

        /*
         * append source to list 
         */
        src_set_first(src_append(src.first_source, result));
        
        /*
         * set current_source if unset 
         */
        if(!src.current_source)
            src_set(result);
    }
    
    /* failed to allocate new source-structure */
    else {
        gui_dialog("No more memory...\n");
    }
    
    return result;
    
}
/**
 * get position of a source inside a list 
 */
int src_listpos(struct video_src *source)
{
    struct video_src *current;
    int count = 0;

    for(current = src.first_source; current;
        current = current->next_source) {
        if(current == source)
            return count;
        count++;
    }

    return -1;
}

/**
 * get source n from list or NULL if not in list 
 */
struct video_src *src_get_n(int n)
{
    struct video_src *result = NULL, *tmp;
    int count = 0;

    if(n >= 0 && n < src_listlen())
    {
        for(tmp = src.first_source; tmp; tmp = tmp->next_source) {
            if(count == n)
            {
                result = tmp;
                break;
            }
            count++;
        }
        
        _VERBOSE2 { if(result) printf("%s(): found.\n", __func__);
            else printf("%s(): not found!\n", __func__); }
    }
    else
    {
        _VERBOSE1 printf("%s(): invalid source -> %d\n", __func__, n);
    }
    return result;

}

/**
 * get amount of source elements in list 
 */
int src_listlen()
{
    struct video_src *current;
    int count = 0;

    for(current = src.first_source; current;
        current = current->next_source) {
        count++;
    }

    return count;
}

/**
 * append a new source to the global list
 */
struct video_src *src_append(struct video_src *first_source,
                                struct video_src *source)
{

    struct video_src *current_source;

    
    _VERBOSE2 printf("%s()\n", __func__);
    if(first_source) {
        for(current_source = first_source;
            current_source->next_source;
            current_source = current_source->next_source);

        /*
         * append source 
         */
        current_source->next_source = source;
        return first_source;
    }
    else {
        return source;
    }
}


/**
 * build pulldown-menu for all sources 
 */
void src_gui_update_pulldown()
{
    GtkWidget *pulldown;
    struct video_src *source;
    char temp[255];
    int count, id = 0;

    
    _VERBOSE2 printf("%s()\n", __func__);
    
    /*
     * get widget 
     */
    if(src.first_source &&
       (pulldown =
        glade_xml_get_widget(gui_get_xml(), "combobox_sources")))
    {

        /*
         * free old menu 
         */
        for(count =
            gtk_tree_model_iter_n_children(gtk_combo_box_get_model
                                           (GTK_COMBO_BOX(pulldown)), NULL);
            count > 0; count--) {

            /*
             * remove first entry 
             */
            gtk_combo_box_remove_text(GTK_COMBO_BOX(pulldown), 0);
        }

        /*
         * get first_source 
         */
        for(source = src.first_source;
            source; source = source->next_source) {

            /*
             * build up some name if necessary
             */
            if(!source->name) {
                snprintf((char *) &temp, 255, "Source #%d", id);
                source->name = (xmlChar *) strdup((char *) &temp);
            }

            /*
             * append name 
             */
            gtk_combo_box_append_text(GTK_COMBO_BOX(pulldown),
                                      (gchar *) source->name);

            /*
             * set as current source if it's the right sensor 
             */
            if(source == src.current_source) {
                gtk_combo_box_set_active(GTK_COMBO_BOX(pulldown), id);
            }

            /*
             * source counter 
             */
            id++;
        }

    }

}


/**
 * refresh source-related GUI parts 
 */
void src_gui_update()
{

    
    _VERBOSE2 printf("%s()\n", __func__);
    
    if(gui_get_xml())
    {
        if(src.current_source) 
        {
            
     
            /* source disabled? */
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
                            (glade_xml_get_widget
                              (gui_get_xml(),
                               "checkbutton_disabled")), 
                                src.current_source->disabled);

            
            /*
             * refresh menus 
             */
            src_gui_update_pulldown();
            sensor_gui_update_pulldown();
   
            gstr_pipeline_is_valid((gchar *) src.current_source->gst_string);
            
            /*
             * set gStreamer pipeline-string 
             */
            gtk_entry_set_text(GTK_ENTRY
                               (glade_xml_get_widget
                                (gui_get_xml(), "entry_gst_string")),
                               g_locale_to_utf8((gchar *) src.current_source->gst_string, -1,
                                    NULL, NULL, NULL));
                                    
    
            /*
             * use tuner? 
             */
            if(src.current_source->tuner) 
            {
                /*
                 * checkbutton 
                 */
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
                                             (glade_xml_get_widget
                                              (gui_get_xml(),
                                               "checkbutton_tuner")), TRUE);
                /*
                 * source 
                 */
                gtk_entry_set_text(GTK_ENTRY
                                   (glade_xml_get_widget
                                    (gui_get_xml(), "entry_input_channel")),
                                    g_locale_to_utf8((gchar *) src.current_source->tuner, -1,
                                    NULL, NULL, NULL));
                                   
                /*
                 * enable 
                 */
                gtk_widget_set_sensitive(glade_xml_get_widget
                                         (gui_get_xml(),
                                          "entry_input_channel"), TRUE);
            }
            else 
            {
                /*
                 * disable 
                 */
                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
                                             (glade_xml_get_widget
                                              (gui_get_xml(),
                                               "checkbutton_tuner")), FALSE);
                gtk_widget_set_sensitive(glade_xml_get_widget
                                         (gui_get_xml(),
                                          "entry_input_channel"), FALSE);
            }
    
            
            if(GST_IS_CAPS(src.current_source->caps))
            {
                
                /*
                 * set cap-text 
                 */
                if(!src.current_source->cap_textbuffer)
                {
                    src.current_source->cap_textbuffer = gtk_text_buffer_new(NULL);
                }
                
                gtk_text_buffer_set_text(src.current_source->cap_textbuffer, 
                                         g_locale_to_utf8(gst_caps_to_string(
                                                src.current_source->caps), -1,
                                        NULL, NULL, NULL), -1);
        
                /*
                 * set capabilities text 
                 */
                gtk_text_view_set_buffer(GTK_TEXT_VIEW(src.textview_caps),
                                         src.current_source->cap_textbuffer);
    
            }
            
            
            /* update sensor GUI */
            sensor_gui_update();
            
        }
    
        
    }
}

/** 
 * @} 
 */
